import unittest
import datetime
import sys
import os

from django.core import management

# Add the tests directory so the testapp is on sys.path
test_root = os.path.dirname(__file__)
sys.path.append(test_root)

# Import testapp's models
import testapp.models
from testapp.models import *


class TestDenormalisation(unittest.TestCase):

    """
    Tests for the denormalisation fields.
    """
    
    def setUp(self):
        """Swaps out various Django calls for fake ones for our own nefarious purposes."""
        
        def new_get_apps():
            return [testapp.models]
        
        from django.db import models
        from django.conf import settings
        models.get_apps_old, models.get_apps = models.get_apps, new_get_apps
        settings.INSTALLED_APPS, settings.OLD_INSTALLED_APPS = (
            ["testapp"],
            settings.INSTALLED_APPS,
        )
        self.redo_app_cache()
        management.call_command('syncdb')
    
    
    def tearDown(self):
        """Undoes what monkeypatch did."""
        
        from django.db import models
        from django.conf import settings
        models.get_apps = models.get_apps_old
        settings.INSTALLED_APPS = settings.OLD_INSTALLED_APPS
        self.redo_app_cache()
        
        # Also delete all model instances
        Agg.objects.all().delete()
        AggFKSource.objects.all().delete()
        AggAllSource.objects.all().delete()
        Mirror.objects.all().delete()
        MirrorSource.objects.all().delete()
    
    
    def redo_app_cache(self):
        from django.db.models.loading import AppCache
        a = AppCache()
        a.loaded = False
        a._populate()
    
    
    def add_agg_sources(self, fk):
        AggFKSource.objects.create(name="s1", parent=fk)
        AggFKSource.objects.create(name="s2", parent=fk)
        AggFKSource.objects.create(name="s3", parent=None)
        AggAllSource.objects.create(integer=1)
        AggAllSource.objects.create(integer=12)
        AggAllSource.objects.create(integer=34)
        AggAllSource.objects.create(integer=67)
    
    
    def testAggCreation(self):
        """
        Tests creation of a new model results in zero'd fields,
        """
        # Add a new Agg
        x = Agg.objects.create()
        # Make sure its two aggregate fields are zero on the initial object
        self.assertEqual(x.children_count, 0)
        self.assertEqual(x.integer_count, 0)
        # Fetch it again, check again
        y = Agg.objects.get(id=x.id)
        self.assertEqual(y.children_count, 0)
        self.assertEqual(y.integer_count, 0)
        # Add some AggSources
        self.add_agg_sources(y)
        # Make a new one
        z = Agg.objects.create()
        self.assertEqual(z.children_count, 0)
        self.assertEqual(z.integer_count, 4)
        # Fetch it again, check again
        a = Agg.objects.get(id=z.id)
        self.assertEqual(a.children_count, 0)
        self.assertEqual(a.integer_count, 4)
    
    
    def testAggChange(self):
        """
        Tests updating of AggregateField values
        """
        # Add a new Agg
        x = Agg.objects.create()
        # Should be 0
        y = Agg.objects.get(id=x.id)
        self.assertEqual(y.children_count, 0)
        self.assertEqual(y.integer_count, 0)
        # Add some AggSources
        self.add_agg_sources(x)
        # Should be 2, 4
        y = Agg.objects.get(id=x.id)
        self.assertEqual(y.children_count, 2)
        self.assertEqual(y.integer_count, 4)
        # Delete some AggSources
        AggFKSource.objects.all()[0].delete()
        AggAllSource.objects.all()[0].delete()
        # Should be 1, 3
        y = Agg.objects.get(id=x.id)
        self.assertEqual(y.children_count, 1)
        self.assertEqual(y.integer_count, 3)
        # Delete all AggSources
        AggFKSource.objects.all().delete()
        AggAllSource.objects.all().delete()
        # Should be 0
        y = Agg.objects.get(id=x.id)
        self.assertEqual(y.children_count, 0)
        self.assertEqual(y.integer_count, 0)
    
    
    def testMirror(self):
        """
        Tests correct values in MirrorFields
        """
        # Create a Source
        s = MirrorSource.objects.create(name="Margaret")
        # Create a Mirror
        x = Mirror.objects.create(other=s)
        y = Mirror.objects.create(other=s)
        # Make sure it has the right value
        self.assertEqual(x.other_name, "Margaret")
        # And in the database
        self.assertEqual(Mirror.objects.get(id=x.id).other_name, "Margaret")
        # Update the Source
        s.name = "Manny"
        s.save()
        self.assertEqual(Mirror.objects.get(id=x.id).other_name, "Manny")
        self.assertEqual(Mirror.objects.get(id=y.id).other_name, "Manny")
        